#pragma once
#include <utility>// for std::forward, std::decay_t

#define Pair CPair

template <typename K, typename V>
class CPair {
public:
    CPair() = default;

    // perfect forwarding constructor (supports move semantics and avoids copying)
    template <typename T1, typename T2>
    CPair(T1&& k, T2&& v) : key(std::forward<T1>(k)), value(std::forward<T2>(v)) {}

    K key;
    V value;
};

template <typename T1, typename T2>
CPair<std::decay_t<T1>, std::decay_t<T2>> MakePair(T1&& k, T2&& v) {
    return CPair<std::decay_t<T1>, std::decay_t<T2>>(
        std::forward<T1>(k),
        std::forward<T2>(v)
    );
}

/**
 *@brief C++17 `CTAD`: Class Template Argument Deduction
 *@note CppVersion >= C++17: you can use `CPair(key, value)` directly without specifying template arguments.
 *       CppVersion < C++17: you should use `MakePair(key, value)` safely(to keep correct types), or: `CPair<K, V>(key, value)` to specify template arguments explicitly.
 */
template <typename T1, typename T2>
CPair(T1&&, T2&&) -> CPair<std::decay_t<T1>, std::decay_t<T2>>;